namespace HZY.Framework.Aop.Attributes;

/// <summary>
/// 耗时统计
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class TimeAttribute : AopMoAttribute
{
    /// <summary>
    /// 定义事件拦截器
    /// </summary>
    public static List<Action<TimeContext, string>> TimeEvents { get; } = [];

    /// <summary>
    /// 备注/描述
    /// </summary>
    public string Remark { get; set; }

    /// <summary>
    /// 耗时统计
    /// </summary>
    /// <param name="remark">备注/描述</param>
    public TimeAttribute(string remark)
    {
        Remark = remark;
    }

    /// <summary>
    /// 方法执行前
    /// </summary>
    /// <param name="context"></param>
    public override void OnEntry(MethodContext context)
    {
        base.OnEntry(context);

        var stopwatch = new Stopwatch();
        //记录 api 执行耗时
        stopwatch.Restart();
        // 传递统计耗时对象
        context.Datas["Stopwatch"] = stopwatch;
        // 开始时间
        context.Datas["StartTime"] = DateTime.UtcNow;
    }

    /// <summary>
    /// 方法执行异常
    /// </summary>
    /// <param name="context"></param>
    public override void OnException(MethodContext context)
    {
    }

    /// <summary>
    /// 方法执行成功后
    /// </summary>
    /// <param name="context"></param>
    public override void OnSuccess(MethodContext context)
    {
    }

    /// <summary>
    /// 获取日志文本
    /// </summary>
    /// <param name="context"></param>
    /// <param name="timeContext"></param>
    /// <returns></returns>
    protected virtual string GetLogText(MethodContext context, TimeContext timeContext)
    {
        var log = @$"
== 【备注: {Remark}】【耗时: {timeContext.ElapsedMilliseconds} 毫秒! , {timeContext.ElapsedMilliseconds / 1000} 秒!】【 {timeContext.StartTime:yyyy-MM-dd HH:mm:ss.fff} ～ {timeContext.EndTime:yyyy-MM-dd HH:mm:ss.fff}】 
== 【类名】
{timeContext.NameSpace + " > " + timeContext.ClassName}
== 【函数】
{timeContext.ReturnTypeName} {timeContext.MethodName}({(timeContext.ParameterStr.Count > 0 ? string.Join(",", timeContext.ParameterStr) : "")}) {{ ... }}
== 【入参】
( {(timeContext.ParameterStr.Count > 0 ? string.Join(",", timeContext.ParameterStr) : "")} )
== 【返回值】
{timeContext.ReturnValue}
";

        return log;
    }

    /// <summary>
    /// 方法退出时，不论方法执行成功还是异常，都会执行
    /// </summary>
    /// <param name="context"></param>
    public override void OnExit(MethodContext context)
    {
        // 获取参数
        if (context.Datas["Stopwatch"] is not Stopwatch stopwatch)
        {
            return;
        }

        stopwatch.Stop();
        var endTime = DateTime.UtcNow;

        // 获取日志对象
        var logger = GetLogger<TimeAttribute>(context);
        if (logger == null)
        {
            return;
        }

        // 对象
        var timeContext = TimeContext.Map(context, Remark, stopwatch, endTime);

        var log = @"
=========================方法执行 [耗时统计] 开始=========================
";

        log += GetLogText(context, timeContext);

        log += @"
=========================方法执行 [耗时统计] 结束=========================
";

        logger.LogWarning(log);

        // 调用事件
        foreach (var item in TimeEvents)
        {
            item.Invoke(timeContext, log);
        }
    }
}